#ifndef SRVCONNECTIONHTTP_H_
#define SRVCONNECTIONHTTP_H_

#include "scHeader.h"
#include <QBuffer>
#include <QHttp>
#include "StateConnection.h"
#include "StateRequest.h"
#include "SrvConnection.h"

namespace sybilpm
{
/**
 * This class acts as a proxy of a remote server connected via http. Protocol issues are encapsulated here,
 * so no http specifics outside this class. It simulates a continuous connection
 * although the underlying protocol may open and close the connection multiple times.
 */
class SrvConnectionHttp : public SrvConnection
{
	Q_OBJECT
	/**
	 * http specific state
	 */
	enum RequestType
	{
		RT_HEAD=0,
		RT_GET,
		RT_POST
	};
	/**
	 * An open class containing data related to a single request.
	 * Note that this class takes ownership of all QBuffer objects.
	 */
	struct Request
	{
		Request(RequestType type, unsigned long transId, QBuffer * dataBuffer, QBuffer * paramBuffer) :
			type(type), state(transId), dBuf(dataBuffer), pBuf(paramBuffer) {}
		~Request() {if(dBuf) delete dBuf; if(pBuf) delete pBuf;}
		RequestType type;
		StateRequest state;
		QBuffer * dBuf, * pBuf;
	};

public:
	/**
	 * Create a new server connection. Before you can use it you have to
	 * activate it by starting a test.
	 *
	 * @param
	 * @see startTest
	 */
	SrvConnectionHttp(QString serverIp, qint16 serverPort, bool useHttps);

	// implementation of SrvConnection
	virtual ~SrvConnectionHttp();
	virtual QString errorString() const;
	// virtual const void * getIdentity() const {return this;}
	virtual bool acceptRequest() const;
	virtual bool acceptTest() const;
	virtual bool isTesting() const {return state.getState()==state.TEST();}
	virtual unsigned long startTest();
	virtual unsigned long startRequest(RequestDescriptor * requDesc, unsigned long transactionId =0, bool bootTransaction =false);
	virtual QBuffer * getData(unsigned long transId);
	virtual void freeData(unsigned long transId);
	virtual void abortAllTransactions();

private:
	typedef QMap<unsigned long, Request *> Requests;
	typedef QMap<int, unsigned long> Requ2Trans; // map http-request IDs to (external) transaction=buffer IDs
	unsigned long createTrans(RequestDescriptor * requDesc, unsigned long transactionId);
	unsigned long id2trans(int id);
	Request * trans2Rq(unsigned long transId);
	QHttp http;
	StateConnection state;
	bool validHeader;
	unsigned long actTrans;
	Requ2Trans r2t;
	Requests requs;
private slots:
	void stateChangeSl(int newState);
	void requSuccessSl(unsigned long transId);
	void requFailedSl(unsigned long transId);
	void httpAuthRequiredSl(const QString & hostname, quint16 port, QAuthenticator * auth);
	void httpDataReadProgressSl(int done, int total);
	void httpDataSendProgressSl(int done, int total);
	void httpDoneSl(bool error);
	void httpProxyAuthRequiredSl(const QNetworkProxy & proxy, QAuthenticator * auth);
	void httpReadyReadSl(const QHttpResponseHeader & resp);
	void httpRequestFinishedSl(int id, bool error);
	void httpRequestStartedSl(int id);
	void httpResponseHeaderReceivedSl(const QHttpResponseHeader & resp);
	void httpSslErrorsSl(const QList<QSslError> & errors);
	void httpStateChangedSl(int httpState);
};

} // namespace sybilpm

#endif /*SRVCONNECTIONHTTP_H_*/
